/* This file is part of MyRename
 * Copyright (C) 2005-2009 Kai-Chieh Ku (kjackie@gmail.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "stdafx.h"
#include "others.h"
#include "preferences.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

size_t strneq(LPCTSTR s1, LPCTSTR s2)
{
	size_t i = sstrlen(s1), j = sstrlen(s2);
	j = min(i, j);
	for (i = 0;i < j;i++)
		if (s1[i] != s2[i])
			return i;
	return i;
}

size_t strndigit(LPCTSTR str)
{
	size_t i, count = sstrlen(str);
	for (i = 0;i < count;i++)
		if (! _istdigit(str[i])) return i;
	return i;
}

int strdigitcmp(LPCTSTR s1, LPCTSTR s2)
{
	size_t s1dlen, s2dlen;
	LPTSTR s1p, s2p, s1end, s2end;

	s1dlen = strndigit(s1);
	s2dlen = strndigit(s2);

	s1end = (LPTSTR) s1 + s1dlen;
	s2end = (LPTSTR) s2 + s2dlen;

	for (s1p = (LPTSTR) s1;*s1p == _T('0');s1p++);
	for (s2p = (LPTSTR) s2;*s2p == _T('0');s2p++);

	if (strndigit(s1p) > strndigit(s2p))
		return 1;
	if (strndigit(s1p) < strndigit(s2p))
		return -1;

	while (s1p < s1end) {
		if (*s1p != *s2p)
			return *s1p - *s2p;
		s1p++;
		s2p++;
	}

	return 0;
}

int smartstrcmp(LPCTSTR s1, LPCTSTR s2)
{
	size_t neq, s1dlen, s2dlen;
	int i, t;

	if (!sstrlen(s1) && !sstrlen(s2))
		return 0;
	if (!sstrlen(s2))
		return 1;
	if (!sstrlen(s1))
		return -1;

	neq = strneq(s1, s2);

	i = (int) neq;
	if (neq > 0) {
		for (;_istdigit(s1[i]);i--);
		if (i < 0) i = 0;
		else if ((size_t) i < neq) i++;
	}

	s1dlen = strndigit(s1 + i);
	s2dlen = strndigit(s2 + i);
	if (s1dlen && s2dlen) {
		t = strdigitcmp(s1 + i, s2 + i);
		if (t) return t;
		return smartstrcmp(s1 + i + s1dlen, s1 + i + s2dlen);
	}

	return sstricmp(s1 + neq, s2 + neq);
}

int smartstricmp(LPCTSTR s1, LPCTSTR s2)
{
	LPTSTR s1t, s2t;
	int t;

	if (!sstrlen(s1) && !sstrlen(s2))
		return 0;
	if (!sstrlen(s2))
		return 1;
	if (!sstrlen(s1))
		return -1;

	s1t = (LPTSTR) malloc((sstrlen(s1) + 1) * sizeof(TCHAR));
	s2t = (LPTSTR) malloc((sstrlen(s2) + 1) * sizeof(TCHAR));

	strToLower(s1t, s1);
	strToLower(s2t, s2);

	t = smartstrcmp(s1t, s2t);

	free(s1t);
	free(s2t);

	return t;
}

size_t sstrlen(LPCTSTR str)
{
	if (str == NULL)
		return 0;
	return _tcslen(str);
}

int sstricmp(LPCTSTR s1, LPCTSTR s2)
{
	if (!sstrlen(s1) && !sstrlen(s2))
		return 0;
	if (!sstrlen(s2))
		return 1;
	if (!sstrlen(s1))
		return -1;
	return _tcsicmp(s1, s2);
}

LPTSTR tmpdir(LPCTSTR path, LPTSTR dir)
{
	size_t len;
	int i, j, r[5];
	TCHAR buf[MAX_PATH + _MAX_FNAME];
	LPTSTR pEnd;

	_tcscpy(buf, path);
	len = _tcslen(path);

	if (buf[len - 1] != _T('\\')) {
		buf[len] = _T('\\');
		buf[len + 1] = _T('\0');
		len++;
	}

	pEnd = buf + len;

	j = 0;
	do {
		j++;

		if (j > 1000)
			return NULL;

		for (i = 0;i < 5;i++) {
			r[i] = rand() + rand();
			r[i] &= 0x0000FFFF;
		}
		_stprintf(pEnd, _T("%04X%04X%04X%04X%04X"), r[0], r[1], r[2], r[3], r[4]);
	} while (!CreateDirectory(buf, NULL));

	_tcscpy(dir, pEnd);

	return dir;
}

int ReplaceNoCase(CString &dest, LPCTSTR pat, LPCTSTR rp)
{
	const size_t patlen = sstrlen(pat), rplen = sstrlen(rp);
	int *MatchPos, bufferLen = _MAX_PATH, iMatchCount = 0, start, len, i;
	const int srclen = dest.GetLength();
	LPTSTR src, lowSrc, lowPat, p1, p2, p3;

	if (patlen == 0 || srclen == 0)
		return 0;

	src = new TCHAR [srclen + 1];
	lowSrc = new TCHAR [srclen + 1];
	lowPat = new TCHAR [patlen + 1];

	strToLower(lowPat, pat);

	//copy a source string and a lower case source string --->
	for (p1 = src, p2 = lowSrc, p3 = dest.GetBuffer();*p1 = *p2 = *p3;p1++, p2++, p3++) {
		if (_istupper(*p2))
			*p2 = _tolower(*p2);
	}
	dest.ReleaseBuffer();
	//copy a source string and a lower case source string <---

	//perform matching--->
	MatchPos = new int [bufferLen];
	for (p1 = lowSrc;p1 = _tcsstr(p1, lowPat);p1 += patlen) {
		if (iMatchCount > bufferLen) {//reallocate buffer
			bufferLen <<= 1;
			int *newBuffer = new int [bufferLen];
			memcpy(newBuffer, MatchPos, sizeof(int) * iMatchCount);
			delete [] MatchPos;
			MatchPos = newBuffer;
		}
		MatchPos[iMatchCount] = (int)(p1 - lowSrc);
		iMatchCount++;
	}
	//perform matching <---

	delete [] lowSrc;
	delete [] lowPat;

	bufferLen = srclen + (int)(rplen - patlen) * iMatchCount;

	ASSERT(bufferLen >= 0);

	if (bufferLen == 0)
		dest = _T("");
	else if (iMatchCount > 0) {//&& bufferLen > 0
		p1 = dest.GetBufferSetLength(bufferLen);
		p2 = src;
		start = 0;
		for (i = 0;i < iMatchCount;i++) {
			len = MatchPos[i] - start;
			if (len > 0) {
				_tcsncpy(p1, p2, len);
				p1 += len;
			}
			if (rplen > 0) {
				_tcscpy(p1, rp);
				p1 += rplen;
			}
			p2 = src + MatchPos[i] + patlen;
			start = MatchPos[i] + (int) patlen;
		}
		if (p2 < src + srclen)
			_tcscpy(p1, p2);
		dest.ReleaseBuffer();
	}

	delete [] MatchPos;
	delete [] src;

	return iMatchCount;
}

bool isInteger(LPCTSTR str)
{
	if (*str == _T('+') || *str == _T('-'))
		str++;
	for (;*str != _T('\0');str++)
		if (! _istdigit(*str))
			return false;
	return true;
}

LPTSTR strToLower(LPTSTR dest, LPCTSTR src)
{
	LPTSTR start = dest;

	while (*dest = *src) {
		if (_istupper(*dest))
			*dest = _tolower(*dest);
		dest++;
		src++;
	}

	return start;
}

LPTSTR strToUpper(LPTSTR dest, LPCTSTR src)
{
	LPTSTR start = dest;

	while (*dest = *src) {
		if (_istlower(*dest))
			*dest = _toupper(*dest);
		dest++;
		src++;
	}

	return start;
}

LPTSTR strnqcpy(LPTSTR dest, LPCTSTR src, size_t num)
{
	size_t i = 0;
	LPTSTR start = dest;

	for (;i < num && (*dest++ = *src++);i++);

	dest[num - 1] = _T('\0');

	return start;
}

int GetFileIcon(LPCTSTR filepath)
{
	SHFILEINFO shInfo = {0};

	shInfo.szDisplayName[0] = _T('\0');
	SHGetFileInfo(filepath, 0, &shInfo, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_SMALLICON);
	DestroyIcon(shInfo.hIcon);

	return shInfo.iIcon;
}

/*
void Big5Fix(LPWSTR str)
{
	for (;*str;str++) {
		if (*str >= 0xF74A && *str <= 0xF79F) //Hiragana
			*str -= 0xC6A9;
		else if (*str >= 0xF6F7 && *str <= 0xF749) //Katakana
			*str -= 0xC6B6;
	}

}
*/

void FullToHalf(LPWSTR str)
{
	for (;*str;str++) {
		if (*str >= 0xFF01 && *str <= 0xFF5E)
			*str -= 0xFEE0; //ASCII 0x21 ~ 0x7E
		else if (*str == 0x3000)
			*str = 0x0020; //ASCII 0x20 <space>
	}
}
